home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / jade / src / stringmem.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  7KB  |  282 lines

  1. /* stringmem.c -- Allocation of small pieces of memory
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4.    This file is part of Jade.
  5.  
  6.    Jade is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    Jade is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with Jade; see the file COPYING.  If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <assert.h>
  26.  
  27. #ifdef NEED_MEMORY_H
  28. # include <memory.h>
  29. #endif
  30.  
  31. /* Initialise SM for the first time. */
  32. int
  33. sm_init(StrMem *sm)
  34. {
  35.     int i;
  36.     for(i = 0; i < NUMBUCKETS; i++)
  37.     {
  38.     NewMList(&(sm->sm_MemBuckets[i].mbu_MemBlocks));
  39.     sm->sm_ChunksPerBlock[i] = MBLOCKSIZE / MCHNK_SIZE((i + 1) * GRAIN);
  40. #ifdef STRMEM_STATS
  41.     sm->sm_AllocCount[i] = sm->sm_FreeCount[i] = 0;
  42. #endif
  43.     }
  44.     sm->sm_MallocChain = NULL;
  45.     return(TRUE);
  46. }
  47.  
  48. /* Release all memory allocated for SM, note that unless the `malloc-chain'
  49.    option is used malloc'd blocks aren't freed. The SM is left ready for
  50.    more allocations to be made.  */
  51. void
  52. sm_kill(StrMem *sm)
  53. {
  54.     int i;
  55.     for(i = 0; i < NUMBUCKETS; i++)
  56.     {
  57.     MemBlock *nxt, *mbl = (MemBlock *)sm->sm_MemBuckets[i].mbu_MemBlocks.mlh_Head;
  58.     while((nxt = (MemBlock *)mbl->mbl_Node.mln_Succ))
  59.     {
  60.         myfree(mbl);
  61.         mbl = nxt;
  62.     }
  63.     NewMList(&sm->sm_MemBuckets[i].mbu_MemBlocks);
  64.     sm->sm_MemBuckets[i].mbu_FreeList = NULL;
  65.     sm->sm_MemBuckets[i].mbu_FreeCount = 0;
  66. #ifdef STRMEM_STATS
  67.     sm->sm_AllocCount[i] = sm->sm_FreeCount[i] = 0;
  68. #endif
  69.     }
  70.     if(sm->sm_UseMallocChain)
  71.     {
  72.     MemChunk *mc = sm->sm_MallocChain;
  73.     while(mc)
  74.     {
  75.         MemChunk *nxtmc = mc->mc_Header.next;
  76.         myfree(mc);
  77.         mc = nxtmc;
  78.     }
  79.     sm->sm_MallocChain = NULL;
  80.     }
  81. }
  82.  
  83. static int
  84. new_memblock(StrMem *sm, MemBucket *mbu, int sizeIndex)
  85. {
  86.     MemBlock *mbl;
  87.     int numchunks = sm->sm_ChunksPerBlock[sizeIndex];
  88.     int chnkbytes = (sizeIndex + 1) * GRAIN;
  89.     mbl = mymalloc(MBLK_SIZE(chnkbytes, numchunks));
  90.     if(mbl)
  91.     {
  92.     MemChunk *mc = mbl->mbl_Chunks;
  93.     int i, mcsiz = MCHNK_SIZE(chnkbytes);
  94.     AddMTail(&mbu->mbu_MemBlocks, &mbl->mbl_Node);
  95.     for(i = 0; i < (numchunks - 1); i++)
  96.     {
  97.         MemChunk *nxt = (MemChunk *)((char *)mc + mcsiz);
  98.         mc->mc_BlkType = MBT_FREE;
  99.         mc->mc_Mem.nextfree = nxt;
  100.         mc = nxt;
  101.     }
  102.     mc->mc_BlkType = MBT_FREE;
  103.     mc->mc_Mem.nextfree = mbu->mbu_FreeList;
  104.     mbu->mbu_FreeList = mbl->mbl_Chunks;
  105.     return(TRUE);
  106.     }
  107.     return(FALSE);
  108. }
  109.  
  110. void *
  111. sm_alloc(StrMem *sm, int size)
  112. {
  113.     MemChunk *mc;
  114.     assert(size > 0);
  115.     if(size > MAXBUCKETSIZE)
  116.     {
  117.     mc = mymalloc(MCHNK_SIZE(size));
  118.     if(mc)
  119.     {
  120. #ifdef STRMEM_STATS
  121.         sm->sm_AllocCount[NUMBUCKETS]++;
  122. #endif
  123.         if(sm->sm_UseMallocChain)
  124.         {
  125.         mc->mc_Header.next = sm->sm_MallocChain;
  126.         sm->sm_MallocChain = mc;
  127.         }
  128.         else
  129.         mc->mc_BlkType = MBT_MALLOC;
  130.     }
  131.     else
  132.         return(NULL);
  133.     }
  134.     else
  135.     {
  136.     MemBucket *mbu;
  137.     int bucket = (size - 1) / GRAIN;
  138.     mbu = &sm->sm_MemBuckets[bucket];
  139.     if(!(mc = mbu->mbu_FreeList))
  140.     {
  141.         if(!new_memblock(sm, mbu, bucket))
  142.         return(NULL);
  143.         if(!(mc = mbu->mbu_FreeList))
  144.         return(NULL);
  145.     }
  146.     mc->mc_BlkType = bucket;
  147.     mbu->mbu_FreeList = mc->mc_Mem.nextfree;
  148. #ifdef STRMEM_STATS
  149.     sm->sm_AllocCount[bucket]++;
  150. #endif
  151.     }
  152.     return(mc->mc_Mem.mem);
  153. }
  154.  
  155. u_char *
  156. sm_strdupn(StrMem *sm, const u_char *old, int len)
  157. {
  158.     char *new = sm_alloc(sm, len + 1);
  159.     if(new)
  160.     {
  161.     memcpy(new, old, len);
  162.     new[len] = 0;
  163.     }
  164.     return(new);
  165. }
  166.  
  167. u_char *
  168. sm_strdup(StrMem *sm, const u_char *str)
  169. {
  170.     return(sm_strdupn(sm, str, strlen(str)));
  171. }
  172.  
  173. /*
  174.  * This scans through all allocated MemBlocks in a MemBucket looking
  175.  * for any which totally consist of unused entrys, any found are
  176.  * released.
  177.  */
  178. static void
  179. flush_bucket(StrMem *sm, int bucketIndex)
  180. {
  181.     MemBlock *mbl = (MemBlock *)sm->sm_MemBuckets[bucketIndex].mbu_MemBlocks.mlh_Head;
  182.     MemBlock *nxt;
  183.     int chnksiz = MCHNK_SIZE((bucketIndex + 1) * GRAIN);
  184.     int numchnks = sm->sm_ChunksPerBlock[bucketIndex];
  185.     while((nxt = (MemBlock *)mbl->mbl_Node.mln_Succ))
  186.     {
  187.     MemChunk *mc = mbl->mbl_Chunks;
  188.     int j;
  189.     for(j = 0; j < numchnks; j++)
  190.     {
  191.         if(mc->mc_BlkType != MBT_FREE)
  192.         break;
  193.         mc = (MemChunk *)((char *)mc + chnksiz);
  194.     }
  195.     if(j == numchnks)
  196.     {
  197.         mc = mbl->mbl_Chunks;
  198.         for(j = 0; j < numchnks; j++)
  199.         {
  200.         MemChunk *last = NULL;
  201.         MemChunk *list = sm->sm_MemBuckets[bucketIndex].mbu_FreeList;
  202.         while(list)
  203.         {
  204.             if(list == mc)
  205.             {
  206.             if(last)
  207.                 last->mc_Mem.nextfree = list->mc_Mem.nextfree;
  208.             else
  209.                 sm->sm_MemBuckets[bucketIndex].mbu_FreeList = list->mc_Mem.nextfree;
  210.             break;
  211.             }
  212.             last = list;
  213.             list = list->mc_Mem.nextfree;
  214.         }
  215.         mc = (MemChunk *)((char *)mc + chnksiz);
  216.         }
  217.         RemoveM(&mbl->mbl_Node);
  218.         myfree(mbl);
  219.     }
  220.     mbl = nxt;
  221.     }
  222. }
  223.  
  224. void
  225. sm_free(StrMem *sm, void *mem)
  226. {
  227.     if(mem)
  228.     {
  229.     MemChunk *mc = (MemChunk *)(((char *)mem) - sizeof(union mc_header));
  230.     int bucketnum = mc->mc_BlkType;
  231.     if(bucketnum == MBT_MALLOC)
  232.     {
  233.         myfree(mc);
  234. #ifdef STRMEM_STATS
  235.         sm->sm_FreeCount[NUMBUCKETS]++;
  236. #endif
  237.     }
  238.     else
  239.     {
  240.         MemBucket *mbu;
  241.         assert(bucketnum <= NUMBUCKETS);
  242.         mbu = &sm->sm_MemBuckets[bucketnum];
  243.         mc->mc_Mem.nextfree = mbu->mbu_FreeList;
  244.         mc->mc_BlkType = MBT_FREE;
  245.         mbu->mbu_FreeList = mc;
  246.         if(sm->sm_FreesBeforeFlush)
  247.         {
  248.         /* check whether to flush this bucket... */
  249.         if(++mbu->mbu_FreeCount >= (sm->sm_FreesBeforeFlush * sm->sm_ChunksPerBlock[bucketnum]))
  250.         {
  251.             mbu->mbu_FreeCount = 0;
  252.             flush_bucket(sm, bucketnum);
  253.         }
  254.         }
  255. #if 0
  256.         if(sm == main_strmem)
  257.         {
  258.         /* Tell gc there's x bytes of data which may be able to be
  259.            reclaimed. This may seem backwards but it makes sense to gc
  260.            (and hence sm_flush()) when a lot of string-bytes have been
  261.            freed.  */
  262.         data_after_gc += (bucketnum + 1) * GRAIN;
  263.         }
  264. #endif
  265. #ifdef STRMEM_STATS
  266.         sm->sm_FreeCount[bucketnum]++;
  267. #endif
  268.     }
  269.     }
  270. }
  271.  
  272. /*
  273.  * called when malloc() fails, tries to release any memory we can
  274.  */
  275. void
  276. sm_flush(StrMem *sm)
  277. {
  278.     int i;
  279.     for(i = 0; i < NUMBUCKETS; i++)
  280.     flush_bucket(sm, i);
  281. }
  282.